# 一、异常
# 执行时检测到的错误称为 ：异常 ，异常不一定导致严重的后果；大多数异常不会被程序处理，而是显示下列错误信息：

# 1、捕获异常的语法
#
# try:
#     可能发生错误的代码
# except 异常类型1:
#     如果捕获到该异常类型1执行的代码
# except 异常类型2:
#     如果捕获到该异常类型2执行的代码
# ......
# 如果尝试执行的代码的异常类型和要捕获的异常类型不一致，则无法捕获异常。
# try 语句的工作原理如下：
# - 首先，执行 try 子句 （try 和 except 关键字之间的（多行）语句）。
# - 如果没有触发异常，则跳过 except 子句，try 语句执行完毕。
# - 如果在执行 try 子句时发生了异常，则跳过该子句中剩下的部分。 如果异常的类型与 except 关键字后指定的异常相匹配，则会执行 except 子句，然后跳到 try/except 代码块之后继续执行。
# - 如果发生的异常与 except 子句 中指定的异常不匹配，则它会被传递到外部的 try 语句中；如果没有找到处理程序，则它是一个 未处理异常 且执行将终止。

# 案例：
import traceback
from traceback import print_tb

# a = 100 / 0

# '23' + 12


try:
    f = open('abc.txt')
    s = f.readline()
    num = int(s.strip())
    print(num)
except FileNotFoundError:
    print(traceback.format_exc())
    print('文件不存在')
except ValueError:
    print(traceback.format_exc())
    print('值不对，不能转换')
except Exception as err:  # Exception是所有异常的父类
    print(err)
    print(traceback.format_exc())
else:
    print('没有异常，很高兴')
finally:
    if f:
        print('不管有没有异常都会执行的代码')
        f.close()
print('程序完成')

# 2、强制抛出异常
# raise 语句支持强制触发指定的异常。比如：如果只想判断是否触发了异常，但并不打算处理该异常，则可以使用更简单的 raise 语句重新触发异常。
# try:
# ...     raise NameError('HiThere')
# ... except NameError:
# ...     print('An exception flew by!')

# 3、异常中的else
# else表示的是如果没有异常要执行的代码。
# try:
#     print(1)
# except Exception as result:
#     print(result)
# else:
#     print('我是else，是没有异常的时候执行的代码')

# 4、Finally语句
# finally表示的是无论是否异常都要执行的代码，例如关闭文件。一般都是做一些清理工作。
# try:
#     f = open('test.txt', 'r')
# except Exception as result:
#     f = open('test.txt', 'w')
# else:
#     print('没有异常，真开心')
# finally:
#     f.close()


# 5、自定义异常类
# 程序可以通过创建新的异常类命名自己的异常。不论是以直接还是间接的方式，异常都应从 Exception 类继承。
#
# 异常类可以被定义成能做其他类所能做的任何事，但通常应当保持简单，它往往只提供一些属性，允许相应的异常处理程序提取有关错误的信息。
#
# 大多数异常命名都以 “Error” 结尾，类似标准异常的命名。

# 自定义异常类，继承Exception
class TooShortInputError(Exception):
    def __init__(self, length, min_len):
        self.length = length
        self.min_len = min_len

    # 设置抛出异常的描述信息
    def __str__(self): #   # str魔法函数， 以后只要有print(对象), 则会自动调用str函数，并且打印str函数的返回值
        return f'你输入的长度是{self.length}, 不能少于{self.min_len}个字符'


def main():
    try:
        con = input('请输入密码：')
        if len(con) < 3:
            raise TooShortInputError(len(con), 3) # 强制输出自定义异常
    except Exception as result:
        print(result)
    else:
        print('密码已经输入完成')
print("**************************")
main()